# ==============================================================================
# SCRIPT 02: DETERMINAÇÃO DO NÚMERO ÓTIMO DE CLUSTERS (K) - 2023
# ==============================================================================

# ------------------------------------------------------------------------------
# 1. OBJETIVO
# ------------------------------------------------------------------------------
# Este script utiliza as mesmas técnicas do script de 2022 para determinar o
# número ideal de clusters (k) para a base de dados de 2023.

# ------------------------------------------------------------------------------
# 2. BIBLIOTECAS NECESSÁRIAS
# ------------------------------------------------------------------------------
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
from scipy.spatial.distance import cdist
import warnings

warnings.filterwarnings("ignore")

# ------------------------------------------------------------------------------
# 3. CONFIGURAÇÕES E CONSTANTES
# ------------------------------------------------------------------------------

# Caminho do arquivo de entrada (gerado pelo script 01)
INPUT_PATH = "../2023_data/base_final_2023.csv"

# Caminhos dos arquivos de saída (gráficos)
ELBOW_PLOT_PATH = "../2023_data/grafico_metodo_cotovelo_2023.png"
SILHOUETTE_PLOT_PATH = "../2023_data/grafico_analise_silhueta_2023.png"

# Lista de segmentos de investimento (features para clusterização)
SEGMENTOS = [
    "Renda Fixa", "Renda Variável", "Investimentos no Exterior",
    "Investimentos Estruturados", "Fundos Imobiliários",
    "Empréstimos Consignados", "Disponibilidades Financeiras"
]

# Range de valores de k para testar
K_RANGE = range(2, 11) # Testaremos de 2 a 10 clusters

# ------------------------------------------------------------------------------
# 4. EXECUÇÃO DO SCRIPT
# ------------------------------------------------------------------------------

print("="*80)
print("INICIANDO DETERMINAÇÃO DO K ÓTIMO - 2023")
print("="*80)

# --- 4.1. Carregamento e Preparação dos Dados ---
print("\n1. Carregando e preparando os dados...")
df = pd.read_csv(INPUT_PATH)

# Selecionar apenas as colunas dos segmentos para a clusterização
X = df[SEGMENTOS]

# Padronizar os dados
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

print(f"  - {len(df)} RPPS carregados.")
print("  - Dados padronizados com sucesso.")

# --- 4.2. Método do Cotovelo (Elbow Method) ---
print("\n2. Executando o Método do Cotovelo...")

distortions = []
for k in K_RANGE:
    kmeanModel = KMeans(n_clusters=k, init='k-means++', n_init=10, random_state=42).fit(X_scaled)
    distortions.append(sum(np.min(cdist(X_scaled, kmeanModel.cluster_centers_, 'euclidean'), axis=1)) / X_scaled.shape[0])
    print(f"  - Testando k={k}... Distorção: {distortions[-1]:.4f}")

plt.figure(figsize=(10, 6))
plt.plot(K_RANGE, distortions, 'bx-')
plt.xlabel('Número de Clusters (k)')
plt.ylabel('Distorção Média')
plt.title('Método do Cotovelo para Determinação do k Ótimo (2023)')
plt.grid(True)
plt.savefig(ELBOW_PLOT_PATH)
print(f"  - Gráfico do Método do Cotovelo salvo em: {ELBOW_PLOT_PATH}")

# --- 4.3. Análise de Silhueta (Silhouette Analysis) ---
print("\n3. Executando a Análise de Silhueta...")

silhouette_scores = []
for k in K_RANGE:
    kmeans = KMeans(n_clusters=k, init='k-means++', n_init=10, random_state=42).fit(X_scaled)
    labels = kmeans.labels_
    score = silhouette_score(X_scaled, labels, metric='euclidean')
    silhouette_scores.append(score)
    print(f"  - Testando k={k}... Score de Silhueta: {score:.4f}")

plt.figure(figsize=(10, 6))
plt.plot(K_RANGE, silhouette_scores, 'bx-')
plt.xlabel('Número de Clusters (k)')
plt.ylabel('Score Médio de Silhueta')
plt.title('Análise de Silhueta para Determinação do k Ótimo (2023)')
plt.grid(True)
plt.savefig(SILHOUETTE_PLOT_PATH)
print(f"  - Gráfico da Análise de Silhueta salvo em: {SILHOUETTE_PLOT_PATH}")

# --- 4.4. Conclusão ---
optimal_k_silhouette = K_RANGE[np.argmax(silhouette_scores)]
print("\n4. Conclusão:")
print("-" * 20)
print(f"O valor de 'k' que maximiza o Score de Silhueta é: {optimal_k_silhouette}")
print("Este é o número de clusters recomendado para a análise de 2023.")

print("\n" + "="*80)
print("DETERMINAÇÃO DO K ÓTIMO DE 2023 CONCLUÍDA!")
print("="*80)
